<template>
  <div class="mini-calendar">
    <!-- 年份选择面板 -->
    <template v-if="showYearPicker">
      <div class="picker-header">
        <button @click="changeYearRange(-10)">
          <el-icon><d-arrow-left /></el-icon>
        </button>
        <span>{{ yearRangeStart }} - {{ yearRangeStart + 9 }}</span>
        <button @click="changeYearRange(10)">
          <el-icon><d-arrow-right /></el-icon>
        </button>
      </div>
      <div class="picker-content">
        <div
          v-for="year in yearRange"
          :key="year"
          class="picker-cell"
          :class="{
            'is-current': year === today.year(),
            'is-selected': isSelectedYear(year),
          }"
          @click="selectYear(year)"
        >
          {{ year }}
        </div>
      </div>
    </template>
    <!-- 月份选择面板 -->
    <template v-else-if="showMonthPicker">
      <div class="picker-header">
        <button @click="changeYear(-1)">
          <el-icon><arrow-left /></el-icon>
        </button>
        <span @click="showYearPicker = true" class="year-text">{{
          currentMonth.year()
        }}</span>
        <button @click="changeYear(1)">
          <el-icon><arrow-right /></el-icon>
        </button>
      </div>
      <div class="picker-content">
        <div
          v-for="(_, index) in 12"
          :key="index"
          class="picker-cell"
          :class="{
            'is-current':
              index === today.month() && currentMonth.year() === today.year(),
            'is-selected': isSelectedMonth(index),
          }"
          @click="selectMonth(index)"
        >
          {{ index + 1 }}月
        </div>
      </div>
    </template>
    <template v-else>
      <!-- 日历头部 -->
      <div class="calendar-header">
        <div>
          <button class="btn-prev-year" @click="prevYear">
            <el-icon><d-arrow-left /></el-icon>
          </button>
          <button class="btn-prev" @click="prevMonth">
            <el-icon><arrow-left /></el-icon>
          </button>
        </div>
        <span class="current-date">
          <!-- 将年月拆分为可点击的部分 -->
          <span class="year-text" @click="showYearPicker = true"
            >{{ currentMonth.format('YYYY') }} 年</span
          >
          <span class="month-text" @click="showMonthPicker = true"
            >{{ currentMonth.format('MM') }} 月</span
          >
        </span>
        <div>
          <button class="btn-next" @click="nextMonth">
            <el-icon><arrow-right /></el-icon>
          </button>
          <button class="btn-next-year" @click="nextYear">
            <el-icon><d-arrow-right /></el-icon>
          </button>
        </div>
      </div>
      <!-- 星期 -->
      <div class="calendar-weeks">
        <span v-for="day in weekDays" :key="day" class="week-day">{{
          day
        }}</span>
      </div>
      <!-- 日期 -->
      <div class="calendar-days">
        <div
          v-for="day in days"
          :key="day.date.valueOf()"
          class="picker-cell"
          :class="{
            'is-today': day.isToday,
            'is-selected': isSelectedDay(day.date),
            'not-current-month': !day.currentMonth,
          }"
          @click="selectDate(day.date)"
          @mouseenter="handleMouseEnter(day.date)"
          @mouseleave="handleMouseLeave"
        >
          {{ day.dayOfMonth }}
        </div>
      </div>
    </template>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted } from 'vue'
import dayjs from 'dayjs'
import { isString } from 'lodash-es'

const props = defineProps(['initDate'])

// 今天
const today = dayjs()

// 当前展示的月份
const currentMonth = ref(dayjs())
// 选中的日期
const selectedDate = ref(null)

// 范围选择状态
const rangeStart = ref(null)
const rangeEnd = ref(null)
// 鼠标悬浮的日期
const hoverDate = ref(null)

// 年份选择和月份选择的状态
const showYearPicker = ref(false)
const showMonthPicker = ref(false)

// 年份范围起始年
const yearRangeStart = computed(() => {
  return Math.floor(currentMonth.value.year() / 10) * 10
})
// 年份范围数组
const yearRange = computed(() => {
  return Array.from({ length: 10 }, (_, i) => yearRangeStart.value + i)
})

// 星期几标题
const weekDays = ['日', '一', '二', '三', '四', '五', '六']

// 计算当前月所有要展示的日期（包括上/下月的溢出部分）
const days = computed(() => {
  const date = currentMonth.value
  const year = date.year()
  const month = date.month()

  // 当月第一天是星期几 (0-6)
  const firstDayOfMonth = dayjs(new Date(year, month, 1))
  const firstDayWeekday = firstDayOfMonth.day()

  // 当月有多少天
  const daysInMonth = date.daysInMonth()

  // 日期数组
  const daysArray = []

  // 添加上月溢出的日期
  const prevMonth = month === 0 ? 11 : month - 1
  const prevMonthYear = month === 0 ? year - 1 : year
  const prevMonthDays = dayjs(
    new Date(prevMonthYear, prevMonth, 1)
  ).daysInMonth()

  for (let i = 0; i < firstDayWeekday; i++) {
    const day = prevMonthDays - firstDayWeekday + i + 1
    daysArray.push({
      date: dayjs(new Date(prevMonthYear, prevMonth, day)),
      dayOfMonth: day,
      currentMonth: false,
      isToday: dayjs(new Date(prevMonthYear, prevMonth, day)).isSame(
        dayjs(),
        'day'
      ),
    })
  }

  // 添加当月日期
  const today = dayjs()
  for (let i = 1; i <= daysInMonth; i++) {
    const date = dayjs(new Date(year, month, i))
    daysArray.push({
      date,
      dayOfMonth: i,
      currentMonth: true,
      isToday: date.isSame(today, 'day'),
    })
  }

  // 添加下月溢出的日期
  const daysNeeded = 42 - daysArray.length // 6行 x 7列 = 42个格子
  const nextMonth = month === 11 ? 0 : month + 1
  const nextMonthYear = month === 11 ? year + 1 : year

  for (let i = 1; i <= daysNeeded; i++) {
    const date = dayjs(new Date(nextMonthYear, nextMonth, i))
    daysArray.push({
      date,
      dayOfMonth: i,
      currentMonth: false,
      isToday: date.isSame(today, 'day'),
    })
  }

  return daysArray
})

// 鼠标进入日期单元格
const handleMouseEnter = (date) => {
  if (props.rangeMode && rangeStart.value && !rangeEnd.value) {
    hoverDate.value = date
  }
}
// 鼠标离开日期单元格
const handleMouseLeave = () => {
  hoverDate.value = null
}

// 修改年份范围
const changeYearRange = (offset) => {
  currentMonth.value = currentMonth.value.year(yearRangeStart.value + offset)
}

// 修改年份
const changeYear = (offset) => {
  currentMonth.value = currentMonth.value.add(offset, 'year')
}
// 选择年份
const selectYear = (year) => {
  currentMonth.value = currentMonth.value.year(year)
  showYearPicker.value = false
  showMonthPicker.value = true // 选完年份后显示月份选择
}
// 选择月份
const selectMonth = (month) => {
  currentMonth.value = currentMonth.value.month(month)
  showMonthPicker.value = false
}

// 切换到上个月
const prevMonth = () => {
  currentMonth.value = currentMonth.value.subtract(1, 'month')
}

// 切换到下个月
const nextMonth = () => {
  currentMonth.value = currentMonth.value.add(1, 'month')
}

// 切换到上一年
const prevYear = () => {
  currentMonth.value = currentMonth.value.subtract(1, 'year')
}
// 切换到下一年
const nextYear = () => {
  currentMonth.value = currentMonth.value.add(1, 'year')
}

// 选择日期
const selectDate = (date) => {
  // 检查所选日期是否来自不同月份
  if (!date.isSame(currentMonth.value, 'month')) {
    // 更新当前月份以显示所点击日期的月份
    currentMonth.value = date
  }

  // 单日期选择
  selectedDate.value = date
}

// 判断年份是否被选中
const isSelectedYear = (year) => {
  return currentMonth.value.year() === year
}

// 判断月份是否被选中
const isSelectedMonth = (month) => {
  return currentMonth.value.month() === month
}

// 判断日期是否被选中
const isSelectedDay = (date) => {
  return selectedDate.value && date.isSame(selectedDate.value, 'day')
}

const setValue = (value) => {
  selectDate(dayjs(value))
}

const getValue = () => {
  return selectedDate.value
}

const initState = () => {
  if (isString(props.initDate)) {
    currentMonth.value = dayjs(props.initDate)
    selectedDate.value = dayjs(props.initDate)
  } else {
    currentMonth.value = dayjs()
    selectedDate.value = null
  }
}

const reset = () => {
  currentMonth.value = dayjs()
  selectedDate.value = null
}

onMounted(() => {
  initState()
})

watch(
  () => props.initDate,
  () => {
    initState()
  },
  {
    once: true,
  }
)

defineExpose({
  setValue,
  getValue,
  reset,
})
</script>

<style scoped>
.mini-calendar {
  width: 300px;
  background-color: #fff;
  padding: 12px;
  font-size: 14px;
}

.calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid #ebeef5;
}

.current-date {
  font-size: 16px;
  color: #606266;
}

.btn-prev,
.btn-next,
.btn-prev-year,
.btn-next-year {
  border: none;
  background: transparent;
  cursor: pointer;
  padding: 6px;
  color: #606266;
  border-radius: 50%;
}

.btn-prev:hover,
.btn-next:hover,
.btn-prev-year:hover,
.btn-next-year:hover {
  color: #409eff;
}

.calendar-weeks {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  margin-bottom: 6px;
}

.week-day {
  text-align: center;
  color: #606266;
  font-size: 12px;
  padding: 5px 0;
}

.calendar-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  row-gap: 8px;
}

.is-today {
  color: #409eff;
  font-weight: bold;
}

.year-text,
.month-text {
  cursor: pointer;
  padding: 0 2px;
}
.year-text:hover,
.month-text:hover {
  color: #409eff;
}
.picker-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 0;
  margin-bottom: 8px;
}
.picker-content {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  row-gap: 8px;
  padding: 8px 0;
}
.picker-cell {
  text-align: center;
  height: 30px;
  line-height: 30px;
  cursor: pointer;
  border-radius: 4px;
}
.picker-cell:hover {
  color: #409eff;
}
.picker-cell.is-current {
  color: #409eff;
  font-weight: bold;
}
.picker-cell.is-selected {
  background-color: #409eff;
  color: white;
  font-weight: bold;
}

.picker-cell.is-selected:hover {
  background-color: #409eff;
  opacity: 0.9;
}

.picker-cell.not-current-month,
.picker-cell.not-current-month:hover {
  color: #c0c4cc;
  background: #ffffff;
  font-weight: normal;
}
</style>
